TypeScript 98.3%
CSS 0.9%
Shell 0.7%
1// Diapositives d'une séance (contenu structuré) — et PDF original via ?pdf=1.2import { NextResponse } from "next/server";3import { createReadStream, existsSync, statSync } from "node:fs";4import { Readable } from "node:stream";5import { resolve } from "node:path";6import { apiError, requireEnrollment } from "@/lib/api.ts";7import { AuthError, requireUser } from "@/lib/auth/session.ts";8import { all, get } from "@/lib/db/index.ts";9import { normalizeCourse } from "@/lib/learning/helpers.ts";1011export async function GET(req: Request, ctx: { params: Promise<{ course: string; week: string }> }) {12 try {13 const user = await requireUser();14 const params = await ctx.params;15 const course = normalizeCourse(params.course);16 requireEnrollment(user.id, course);17 const week = parseInt(params.week, 10);18 if (!Number.isInteger(week) || week < 1 || week > 14) throw new AuthError(404, "Séance inconnue.");1920 const doc = get<{ id: number; title: string; path: string }>(21 "SELECT id, title, path FROM documents WHERE course_code = ? AND doc_type = 'slides' AND week = ? AND visible_to_students = 1",22 course, week23 );24 if (!doc) throw new AuthError(404, "Séance introuvable.");2526 // PDF original compilé (même chemin que la source .tex)27 if (new URL(req.url).searchParams.get("pdf") === "1") {28 const pdfPath = resolve(process.cwd(), "..", doc.path.replace(/\.tex$/, ".pdf"));29 if (!existsSync(pdfPath)) return NextResponse.json({ error: "PDF non disponible pour cette séance." }, { status: 404 });30 const size = statSync(pdfPath).size;31 const stream = Readable.toWeb(createReadStream(pdfPath)) as ReadableStream;32 return new Response(stream, {33 headers: {34 "Content-Type": "application/pdf",35 "Content-Length": String(size),36 "Content-Disposition": `inline; filename="${course}-seance${String(week).padStart(2, "0")}.pdf"`,37 "Cache-Control": "private, max-age=3600",38 },39 });40 }4142 const slides = all<{ ref_number: number; title: string; section_title: string; display_content: string; box_types: string }>(43 `SELECT ref_number, title, section_title, display_content, box_types44 FROM chunks WHERE document_id = ? AND ref_type = 'slide' ORDER BY ref_number, seq`,45 doc.id46 );47 return NextResponse.json({ deck: { week, title: doc.title }, slides });48 } catch (e) {49 return apiError(e);50 }51}52